<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <input type="file" name="" id="file" onchange="changeFile()" >
  <img src="" class="image" alt="">
  <button onclick="upLoadFile()" >上传</button>
  <input class="message" type="text" oninput="changeValue()">
</body>
</html>
<script src="http://cdn.staticfile.org/spark-md5/3.0.0/spark-md5.min.js"></script>
<script>
  let oInp = document.querySelector(".message")
  let Img = document.querySelector(".image")
  let file = null
  function changeValue() {
    console.log(oInp.value);
  }
  // 修改上传文件
  function changeFile() {
    let DOM = document.getElementById("file")
    file = DOM.files[0]
    console.log(file);
  }
  
  // 上传文件按钮
  async function upLoadFile() {
    //利用浏览器空闲时间workLoop计算整个文件md5编码
    let chunks  = createFileChunk(file)
    // let res = await calculateHashIdle(chunks);
    // 抽样hash 布隆过滤器抽样 1GB文件抽样后5MB以内获取md5编码
    // let res = await calculateHashSample([])
    // 使用worker开启第二条线程处理获取md5编码
    let res = await calculateHashWorker(chunks)
    methodCallback(res);
  }
  function methodCallback(data) {
    // MD5辨识码用户断点续传等场景标识文件唯一符号
    console.log("methodCallBack, 文件唯一辨识码：", data);
  }
  function createFileChunk(file, size = 1024 * 1024 * 2) {
    let chunks = []
    let cur = 0
    while(cur < file.size) {
      chunks.push({index: cur, file: file.slice(cur, cur + size)})
      cur += size
    }
    return chunks
  }
  // 使用worker开启第二条线程处理获取md5编码
  function calculateHashWorker(chunks) {
    return new Promise(resole => {
      let worker = new Worker("http://172.18.11.1:8080/worker.js")
      worker.postMessage({chunks:chunks})
      worker.onmessage = e => {
        const { hash, type, progress } = e.data
        if(type == "0") {
          console.log(`进度完成${progress}%`);
          resole(hash)
        }else {
          console.log(`未完成进度${progress}%`);
        }
      }
    })
  }
  // 抽样hash 布隆过滤器抽样 1GB文件抽样后5MB以内获取md5编码
  async function calculateHashSample() {
    return new Promise(resole => {
      const spark = new SparkMD5.ArrayBuffer()
      var reader = new FileReader()
      const fileCopy = file
  
      const size = file.size
      const offset = 2 * 1024 * 1024;
      let chunks = [file.slice(0, offset)]
      let cur = offset
      while(cur < size) {
        if(cur + offset >= size) {
          chunks.push(file.slice(cur, cur + offset))
        }else {
          const mid = cur + offset / 2
          const end = cur + offset
          chunks.push(cur, cur + 2)
          chunks.push(mid, mid + 2)
          chunks.push(end - 2, end)
        }
        cur += offset
      }
      reader.readAsArrayBuffer(new Blob(chunks))
      reader.onload = function (e) {
        spark.append(e.target.result)
        resole(spark.end())
      }
    })
  }
  //利用浏览器空闲时间workLoop计算整个文件md5编码
  async function calculateHashIdle(chunk) {
    let chunks = [...chunk]
    console.log(chunks.length);
    return new Promise(resole => {
      const spark = new SparkMD5.ArrayBuffer()
      let count = 0
      const appendToSpark = async file => {
        return new Promise(resole => {
          var reader = new FileReader();
          reader.readAsArrayBuffer(file.slice(0, 1024 * 1024 * 10));
          reader.onload=function(e){
            spark.append(e.target.result)
            resole()
          }
        })
        console.log(file);
      }
      const workLoop = async deadLine => {
        while( count < chunks.length && deadLine.timeRemaining() > 1) {
          console.log(chunks[count].index);
          await appendToSpark(chunks[count].file)
          count++
          if(count < chunks.length) {
            console.log(`未完成进度count:${count},${(count * 100 / chunks.length).toFixed(2)}%`);
          }else {
            console.log(`进度100%`);
            // console.log(`完成 编码为：${spark.end()}`);
            resole(spark.end())
          }
        }
        if(count < chunks.length) {
          window.requestIdleCallback(workLoop)
        }
      }
      window.requestIdleCallback(workLoop)
    })
  }
</script>